package com.xiyou.luckdraw.api.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.xiyou.luckdraw.api.converter.UserInfoConverter;
import com.xiyou.luckdraw.api.dal.entitys.UserInfo;
import com.xiyou.luckdraw.api.dal.mapper.luckdraw.UserInfo1Mapper;
import com.xiyou.luckdraw.api.dal.mapper.luckyelite.UserInfo2Mapper;
import com.xiyou.luckdraw.api.dto.user.*;
import com.xiyou.luckdraw.api.service.IUserInfoService;
import com.xiyou.luckdraw.common.constants.ResultCodeConstants;
import com.xiyou.luckdraw.common.enums.UserInfoEnum;
import com.xiyou.luckdraw.common.exception.ExceptionProcessorUtils;
import com.xiyou.luckdraw.common.utils.DateUtils;
import com.xiyou.luckdraw.common.utils.PageResult;
import com.xiyou.luckdraw.common.utils.ReqUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @ClassName: UserInfoServiceImpl
 * @Description:
 * @author: limingxing
 * @Date: 2019-10-11 16:59
 */
@Slf4j
@Service
public class UserInfoServiceImpl implements IUserInfoService {

    @Autowired
    private UserInfo1Mapper userInfo1Mapper;

    @Autowired
    private UserInfo2Mapper userInfo2Mapper;

    @Autowired
    private UserInfoConverter userInfoConverter;

    @Autowired
    @Qualifier(value = "luckykingMongoTemplate")
    MongoTemplate luckykingMongoTemplate;

    @Autowired
    @Qualifier(value = "luckyeliteMongoTemplate")
    MongoTemplate luckyeliteMongoTemplate;

    //王者: luckdraw,吃鸡: luckyelite
    @Override
    public UserInfoListResponse getUserList(UserInfoListRequest request) {
        log.error("Begin UserInfoServiceImpl.getUserList request : {}", request);
        UserInfoListResponse response = new UserInfoListResponse();
        try {
            request.requestCheck();
            PageHelper.startPage(request.getPage(), request.getSize());
            String datasourceType = ReqUtils.getDatasourceType();
            List<UserInfo> userList = null;
            if (StringUtils.isNotEmpty(request.getStartTime())) {
                request.setStartTime(DateUtils.timeStamp2Date(request.getStartTime(), "YYYY-MM-dd"));
            }
            if (StringUtils.isNotEmpty(request.getEndTime())) {
                request.setEndTime(DateUtils.timeStamp2Date(request.getEndTime(), "YYYY-MM-dd"));
            }
            if (StringUtils.isNotBlank(datasourceType) && "luckdraw".equals(datasourceType)) {
                userList = userInfo1Mapper.selectUserByExample(request);
            } else {
                userList = userInfo2Mapper.selectUserByExample(request);
            }
            PageInfo pageInfo = new PageInfo(userList);
//            List<UserInfoListDto> userInfoListDtoList = userInfoConverter.userInfos2Dto(userList);
            List<UserInfoListDto> userInfoListDtoList = this.userInfosConverterDto(userList, datasourceType);

            response.setUserList(userInfoListDtoList);
            response.setTotal(pageInfo.getTotal());
            response.setCode(ResultCodeConstants.SUCCESS.getCode());
            response.setMsg(ResultCodeConstants.SUCCESS.getMessage());
        } catch (Exception e) {
            log.error("UserInfoServiceImpl.getUserList Occur Exception : {}", e);
            ExceptionProcessorUtils.wrapperHandlerException(response, e);
        }
        return response;
    }


    private List<UserInfoListDto> userInfosConverterDto(List<UserInfo> userList, String datasourceType) {
        if (userList == null) {
            return null;
        }
        List<UserInfoListDto> list = new ArrayList<UserInfoListDto>(userList.size());
        for (UserInfo userInfo : userList) {
            UserInfoListDto userInfoListDto = new UserInfoListDto();
            userInfoListDto.setId(userInfo.getId());
            userInfoListDto.setUserId(userInfo.getUserId());
            userInfoListDto.setTntegralNum(userInfo.getTntegralNum());
            userInfoListDto.setCoupon(userInfo.getCoupon());
            userInfoListDto.setAnswerCount(userInfo.getAnswerCount());
            userInfoListDto.setPhone(userInfo.getPhone());
            userInfoListDto.setNickName(userInfo.getNickName());
            userInfoListDto.setContact(userInfo.getContact());
            userInfoListDto.setEnabled(userInfo.getEnabled());
            userInfoListDto.setPhoto(userInfo.getPhoto());
            userInfoListDto.setBirth(userInfo.getBirth());
            userInfoListDto.setGender(userInfo.getGender());
            userInfoListDto.setCreateTime(userInfo.getCreateTime());
            userInfoListDto.setUpdateTime(userInfo.getUpdateTime());
            Query query = new Query();
            VisitorRecordDto visitorRecordDto = null;
            query.addCriteria(Criteria.where("userId").is(userInfo.getUserId()));
            if (StringUtils.isNotBlank(datasourceType) && "luckdraw".equals(datasourceType)) {
                visitorRecordDto = luckykingMongoTemplate.findOne(query, VisitorRecordDto.class);
            } else {
                visitorRecordDto = luckyeliteMongoTemplate.findOne(query, VisitorRecordDto.class);
            }
            if (null != visitorRecordDto) {
                userInfoListDto.setLastTime(visitorRecordDto.getLastTime());
                userInfoListDto.setIpAddress(visitorRecordDto.getIpAddress());
                userInfoListDto.setVisitsSumCount(visitorRecordDto.getVisitsSumCount());
            }
            list.add(userInfoListDto);
        }

        return list;
    }

    @Override
    public UpdateUserInfoResponse updateByUserId(UpdateUserInfoRequest request) {
        log.error("Begin UserInfoServiceImpl.updateByUserId request : {}", request);
        UpdateUserInfoResponse response = new UpdateUserInfoResponse();
        try {
            request.requestCheck();
            UserInfo userInfo = new UserInfo();
            userInfo.setUserId(request.getUserId());

            userInfo.setEnabled(request.getEnabled());
            String datasourceType = ReqUtils.getDatasourceType();
            Integer result = 0;
            if (StringUtils.isNotBlank(datasourceType) && "luckdraw".equals(datasourceType)) {
                result = userInfo1Mapper.updateUserBySelective(userInfo);
            } else {
                result = userInfo2Mapper.updateUserBySelective(userInfo);
            }
            if (result > 0) {
                response.setCode(ResultCodeConstants.SUCCESS.getCode());
                response.setMsg(ResultCodeConstants.SUCCESS.getMessage());
            } else {
                response.setCode(ResultCodeConstants.DATA_NOT_EXISTS.getCode());
                response.setMsg(ResultCodeConstants.DATA_NOT_EXISTS.getMessage());
            }

        } catch (Exception e) {
            log.error("UserInfoServiceImpl.getUserList Occur Exception : {}", e);
            ExceptionProcessorUtils.wrapperHandlerException(response, e);
        }
        return response;
    }

    @Override
    public List downLoadExcel(HttpServletRequest servletRequest) {
        log.error("Begin UserInfoServiceImpl.updateByUserId request ");
        try {
            UserInfoListRequest listRequest = new UserInfoListRequest();

            String startTime = servletRequest.getParameter("starTime");
            if (startTime != null && !startTime.equals("")) {
                listRequest.setStartTime(startTime);
            }
            String endTime = servletRequest.getParameter("endTime");
            if (endTime != null && !endTime.equals("")) {
                listRequest.setEndTime(endTime);
            }

            String datasourceType = servletRequest.getParameter("datasourceType");
            List<UserInfo> userList = null;
            if (StringUtils.isNotBlank(datasourceType) && "luckdraw".equals(datasourceType)) {
                userList = userInfo1Mapper.selectUserByExample(listRequest);
            } else {
                userList = userInfo2Mapper.selectUserByExample(listRequest);
            }
            List<Map> resultList = new ArrayList<>();
            for (UserInfo userInfo : userList) {
                Map map = new HashMap();
                map.put("id", userInfo.getId());
                map.put("userId", userInfo.getUserId());
                map.put("tntegralNum", userInfo.getTntegralNum());
                map.put("coupon", userInfo.getCoupon());
                map.put("answerCount", userInfo.getAnswerCount());
                map.put("phone", userInfo.getPhone());
                map.put("nickName", userInfo.getNickName());
                if (1 == userInfo.getEnabled()) {
                    map.put("enabled", "启用");
                } else if (2 == userInfo.getEnabled()) {
                    map.put("enabled", "弃用");
                }
                map.put("photo", userInfo.getPhoto());
                if (1 == userInfo.getGender()) {
                    map.put("gender", "男");
                } else if (2 == userInfo.getEnabled()) {
                    map.put("gender", "女");
                }
                map.put("createTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(userInfo.getCreateTime()));
                resultList.add(map);
            }
            return resultList;
        } catch (Exception e) {
            log.error("UserInfoServiceImpl.getUserList Occur Exception : {}", e);
        }
        return null;
    }

    @Override
    public CountUserWeekResponse selectCountWeek() {
        log.error("Begin UserInfoServiceImpl.selectCountWeek ");
        CountUserWeekResponse response = new CountUserWeekResponse();
        String datasourceType = ReqUtils.getDatasourceType();
        try {
            List<Map> result = null;
            if (StringUtils.isNotBlank(datasourceType) && "luckdraw".equals(datasourceType)) {
                result = userInfo1Mapper.selectCountWeek();
            } else {
                result = userInfo2Mapper.selectCountWeek();
            }
            response.setList(result);
            response.setCode(ResultCodeConstants.SUCCESS.getCode());
            response.setMsg(ResultCodeConstants.SUCCESS.getMessage());
        } catch (Exception e) {
            log.error("UserInfoServiceImpl.selectCountWeek Occur Exception : {}", e);
            ExceptionProcessorUtils.wrapperHandlerException(response, e);
        }
        return response;
    }

    @Override
    public UserInfoListResponse selectActiveUser(ActiveUserRequest request) {
        log.error("Begin UserInfoServiceImpl.selectActiveUser request: {}", request);
        UserInfoListResponse response = new UserInfoListResponse();
        try {
            String startTime = "";
            String endTime = "";
            request.requestCheck();
            if (StringUtils.isNotEmpty(request.getStartTime())) {
                startTime = DateUtils.timeStamp2Date(request.getStartTime(), "yyyy-MM-dd HH:mm:ss");
            } else {
                startTime = DateUtils.timeStamp2Date(String.valueOf(DateUtils.getPrev(new Date()).getTime()), "yyyy-MM-dd HH:mm:ss");
            }
            if (StringUtils.isNotEmpty(request.getEndTime())) {
                endTime = DateUtils.timeStamp2Date(request.getEndTime(), "yyyy-MM-dd HH:mm:ss");
            } else {
                endTime = DateUtils.timeStamp2Date(String.valueOf(new Date().getTime()), "yyyy-MM-dd HH:mm:ss");
            }
            String datasourceType = ReqUtils.getDatasourceType();

            Query query = new Query(Criteria.where("lastTime").gte(startTime).lte(endTime));
            PageResult pageResult = this.pageQuery(query, VisitorRecordDto.class, datasourceType, request.getSize(), request.getPage(), "lastTime", request.getSort());
            if (StringUtils.isNotBlank(datasourceType) && "luckdraw".equals(datasourceType)) {
                List<VisitorRecordDto> recordDtoList = pageResult.getList();
                if (null != recordDtoList) {
                    List<UserInfoListDto> userInfoDtoList = new ArrayList<>(recordDtoList.size());
                    for (VisitorRecordDto dto : recordDtoList) {
                        UserInfo userInfo = userInfo1Mapper.selectActiveUserId(dto.getUserId());
                        if (null != userInfo) {
                            UserInfoListDto userInfoDto = userInfoConverter.req2UserInfo(userInfo);
                            userInfoDto.setIpAddress(dto.getIpAddress());
                            userInfoDto.setLastTime(dto.getLastTime());
                            userInfoDto.setVisitsSumCount(dto.getVisitsSumCount());
                            userInfoDtoList.add(userInfoDto);
                        }
                    }
                    response.setUserList(userInfoDtoList);
                    response.setTotal(pageResult.getTotal());

                }
            } else {
                List<VisitorRecordDto> recordDtoList = pageResult.getList();
                if (null != recordDtoList) {
                    List<UserInfoListDto> userInfoDtoList = new ArrayList<>(recordDtoList.size());
                    for (VisitorRecordDto dto : recordDtoList) {
                        UserInfo userInfo = userInfo1Mapper.selectActiveUserId(dto.getUserId());
                        if (null != userInfo) {
                            UserInfoListDto userInfoDto = userInfoConverter.req2UserInfo(userInfo);
                            userInfoDto.setIpAddress(dto.getIpAddress());
                            userInfoDto.setLastTime(dto.getLastTime());
                            userInfoDto.setVisitsSumCount(dto.getVisitsSumCount());
                            userInfoDtoList.add(userInfoDto);
                        }
                    }
                    response.setUserList(userInfoDtoList);
                    response.setTotal(pageResult.getTotal());

                }
            }

            response.setCode(ResultCodeConstants.SUCCESS.getCode());
            response.setMsg(ResultCodeConstants.SUCCESS.getMessage());
        } catch (Exception e) {
            log.error("UserInfoServiceImpl.selectActiveUser Occur Exception : {}", e);
            ExceptionProcessorUtils.wrapperHandlerException(response, e);
        }
        return response;
    }

    @Override
    public CountUserWeekResponse countActiveUser() {
        List listMap = new ArrayList<>(7);
        log.error("Begin UserInfoServiceImpl.countActiveUser ");
        CountUserWeekResponse response = new CountUserWeekResponse();
        String datasourceType = ReqUtils.getDatasourceType();
        for (int i = 0; i < 7; i++) {
            Map<String, Object> map = new LinkedHashMap<>(1);
            String time = DateUtils.getPastDate(i);
            String startTime = DateFormatUtils.format(DateUtils.getDate(time), "yyyy-MM-dd 00:00:00");
            String endTime = DateFormatUtils.format(DateUtils.getDate(time), "yyyy-MM-dd 23:59:59");
            Query query = new Query(Criteria.where("lastTime").gte(startTime).lte(endTime));
            long total = 0;
            if (StringUtils.isNotBlank(datasourceType) && "luckdraw".equals(datasourceType)) {
                total = luckykingMongoTemplate.count(query, VisitorRecordDto.class);
            } else {
                total = luckyeliteMongoTemplate.count(query, VisitorRecordDto.class);
            }
            map.put("createTime", time);
            map.put("counts", total);
            listMap.add(map);
        }
        response.setList(listMap);
        response.setCode(ResultCodeConstants.SUCCESS.getCode());
        response.setMsg(ResultCodeConstants.SUCCESS.getMessage());
        return response;
    }

    /**
     * 分页查询.
     *
     * @param query       Mongo Query对象，构造你自己的查询条件.
     * @param entityClass Mongo collection定义的entity class，用来确定查询哪个集合.
     * @param pageSize    分页的大小.
     * @param pageNum     当前页.
     * @param <T>         collection定义的class类型.
     * @param <R>         最终返回时，展现给页面时的一条记录的类型。
     * @param sortStr     排序字段
     * @return PageResult，一个封装page信息的对象.
     */
    public <T, R> PageResult<R> pageQuery(Query query, Class<T> entityClass, String datasourceType,
                                          Integer pageSize, Integer pageNum, String sortStr, String sortType) {
        //分页逻辑
        long total = 0;
        if (StringUtils.isNotBlank(datasourceType) && "luckdraw".equals(datasourceType)) {
            total = luckykingMongoTemplate.count(query, entityClass);
        } else {
            total = luckyeliteMongoTemplate.count(query, entityClass);
        }
        final Integer pages = (int) Math.ceil(total / (double) pageSize);

        final Criteria criteria = new Criteria();
        int skip = pageSize * (pageNum - 1);
        query.skip(skip).limit(pageSize);

        List<T> entityList = null;
        Sort sort = null;
        if (sortType.equals("DESC")) {
            sort = new Sort(Lists.newArrayList(new Sort.Order(Sort.Direction.DESC, sortStr)));
        } else {

            sort = new Sort(Lists.newArrayList(new Sort.Order(Sort.Direction.ASC, sortStr)));
        }
        if (StringUtils.isNotBlank(datasourceType) && "luckdraw".equals(datasourceType)) {
            entityList = luckykingMongoTemplate.find(query.addCriteria(criteria).with(sort), entityClass);
        } else {
            entityList = luckyeliteMongoTemplate.find(query.addCriteria(criteria).with(sort), entityClass);
        }
        final PageResult<R> pageResult = new PageResult<>();
        pageResult.setTotal(total);
        pageResult.setPages(pages);
        pageResult.setPageSize(pageSize);
        pageResult.setPageNum(pageNum);
        pageResult.setList((List<R>) entityList);
        return pageResult;
    }

}

